/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package tal.drivechain.chain;

import tal.drivechain.chain.script.ScriptCommand;
import tal.drivechain.chain.script.ScriptGenerator;
import tal.drivechain.module.xmlconfig.PropertyInfo;
import tal.drivechain.parsing.ParsingAid;
import tal.drivechain.parsing.Tokenizer;
import tal.drivechain.variable.SetProperty;

/**
 * Represents all the properties one module exports to the chain.
 * @author eisental
 */
public class NodeExport implements ScriptGenerator {
    private ChainNode node;
    private String[] properties;

    /**
     *
     * @param node The module instance that is exporting properties.
     * @param properties An array of names of exported properties of the module.
     */
    public NodeExport(ChainNode node, String[] properties) {
        this.properties = properties;
        this.node = node;
    }

    /**
     * Creates a ModuleExport object from the following command syntax:
     *      export instanceName [{property;...;property}]
     *
     * @param export A ScriptCommand in proper syntax.
     * @param parent The chain that will export module properties.
     * @return A ModuleExport object that can be added to the chain export list (parent.getExports()).
     */
    public static NodeExport parseModuleExport(ScriptCommand export, Chain parent) {
        String nodeName = export.getArg1();
        ChainNode node = parent.getChild(nodeName);
        if (node==null)
            throw new IllegalArgumentException("Node " + nodeName + " was not found in chain " + parent.getPath());

        String[] props;
        if (export.getArg2().trim().length()==0) {
            props = new String[node.getNodeInfo().getProperties().size()];
            int i=0;
            for (PropertyInfo p : node.getNodeInfo().getProperties()) {
                props[i] = p.getName(); i++;
            }
        } else {
            if (!ParsingAid.checkNesting(export.getArg2(), '{', '}'))
                throw new IllegalArgumentException("Invalid export command syntax. should be: export <instance-name> {<property>;...;<property>}");
            props = new Tokenizer(export.getArg2().substring(1, export.getArg2().length()-1), ';').getTokens();

        }

        return new NodeExport(node, props);

    }

    /**
     *
     * @return The module instance that is exported.
     */
    public ChainNode getExportedNode() {
        return node;
    }

    /**
     *
     * @return All properties exported by this ModuleExport object.
     */
    public String[] getProperties() {
        return properties;
    }

    /**
     * Sets a value for a property that is exported by this ModuleExport.
     * @param propName Name of the property (without module instance name).
     * @param value A value string that will be parsed into a property value object (According to the property parser) and set.
     * @param flag The property will be set according to this flag.
     */
    public void setProperty(String propName, Object value, SetProperty.Flag flag) {
        boolean found = false;
        for (String p : properties)
            if (p.equals(propName))
                found = true;

        if (!found)
            throw new IllegalArgumentException(propName + " is not an exported property of " + node.getName());

        node.setProperty(propName, value, flag);


    }

    public String generateScript() {
        String ret = "export " + node.getName() + " {";
        for (String prop : properties)
            ret += "\n\t" + prop + ";";
        return ret + "\n};";
    }

    Object getProperty(String propName) {
        boolean found = false;
        for (String p : properties)
            if (p.equals(propName))
                found = true;

        if (!found)
            throw new IllegalArgumentException(propName + " is not an exported property of " + node.getName());

        return node.getProperty(propName);
    }
}
